#!/usr/bin/env python
"""The manager proxy will provide an interface to Asterisk AMI and clients"""
import socket
import logging 
import Queue
import sys
from messages.actions import action_login 
from messages import message
import exception
import os
	
class AstBridgeManager(object):
	"""Asterisk Manager Proxy class.

	AstBridgeManager will function as a bridge between Asterisk AMI and AMI client.
	It will help to process multiple concurrent client connections to Asterisk AMI.
																		AMI
	AMI client <--------> AstBridgeManager (Asterisk Manager Proxy) <-----------> Asterisk
	"""
	def __init__(self, asterisksrv, amiport, username, secret):
		"""Instance initialization after the instance is created"""
		self.asterisksrv = asterisksrv # Asterisk server host (ip or name)
		self.amiport = amiport # AMI port where the Asterisk server is listenning
		self.username = username # Username to connect to Asterisk server
		self.secret = secret # Secret(Password) to connect to Asterisk server
		self.socket = None
	
		self.response = None
		self.event = None
		self.message_queue = Queue.Queue()
		self.response_queue = Queue.Queue()
		self.event_queue = Queue.Queue()
		self.current_processing_message = ''
		self.incoming_queue = dict()

		"""Connect to Asterisk server via AMI port"""
		try:
			logging.info('Connecting to Asterisk server %s at port %s' %(self.asterisksrv, self.amiport))
			#Create a new TCP socket
			self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			self.socket.connect((self.asterisksrv, self.amiport))
			logging.info('Successfully connected to Asterisk Server %s at port %s....' \
							%(self.asterisksrv, self.amiport))	
			
		except Exception as err:
			logging.error('Failed to connect to Asterisk server (%s )' % (err[0], ))
			sys.exit(2)

		try:			
			#read first response from server (welcome banner)
			bytes = self.socket.recv(4096)
			logging.debug('Welcome banner: %s ' %bytes) 
			raise exception.IncorrectBanner()
			if bytes.startswith('Asterisk Call Manager'):
				self.login()
			else:
				raise exception.IncorrectBanner()
		except Exception as err:
			logging.error('Authentication failure (%s )' % (err[0], ))
			sys.exit(2)	

	def login(self):
		try: 
			logging.debug('Authenticating.......') 
			action_to_send = action_login.ActionLogin(self.username, self.secret)
			self.send_action(action_to_send)
			self.process()
		except Exception as err:
			logging.error('Failed to authenticate %s' %err[0])
			sys.exit(2)
		
  	def disconnect(self):
		"""Disconnect from Asterisk server.
		Do some socket cleanning tasks.
		"""
		logging.info('Cleanup: closing socket')
		if self.socket:			
			self.socket.shutdown(socket.SHUT_RDWR)
			self.socket.close()
		self.socket = None

	def send_action(self, action):
		"""Send Action to Asterisk server"""		
		self.socket.send(action.serialize())
			
	def read_packets (self):
		logging.debug('Reading incomming messasges...........')
		"""Reads a complete message over the stream until EOM."""
		
		bytes = ''		
		if self.socket:
			try:
				bytes = self.socket.recv(4096)
			except Exception as err:
				logging.error('Error found when receiving packets from Asterisk server. Error: %s' %err[0])
				sys.exit(2)		
					
		self.current_processing_message += bytes
		#find position of the EOM token in the messages
		marker = self.current_processing_message.find(message.AMI_Message.EOM)
		logging.debug('Message received (length = %s): \n %s' \
						%(len(self.current_processing_message), self.current_processing_message))
		logging.debug('Marker starting value: %s' %marker)
		while ( marker != -1): #found the EOM token
			#get the whole message
			msg = self.current_processing_message[:marker]
			#reset the current processing message
			self.current_processing_message = \
						self.current_processing_message[marker+len(message.AMI_Message.EOM):]
			#add the message to our message queue for processing later
			self.message_queue.put(msg)
			#find next message
			marker = self.current_processing_message.find(message.AMI_Message.EOM)
			logging.debug('Marker value: %s' %marker)	

	def dispatch_packets(self):
		logging.debug('Dispatching messages.......')
		while not self.message_queue.empty():
			#fetch next message on our message queue
			msg = self.message_queue.get() 
			logging.debug('Message processed (length=%s): \n %s' %(len(msg),msg))		    
			msg = msg.strip()		
		
			#Reponse message
			if msg.lower().startswith('response:'):
				logging.debug('Response message received: \n %s'%msg)
				self.response = message.Response(msg)
				logging.debug('Response object created successfully \n %s' %self.response.serialize())
			#Event message
			elif msg.lower().startswith('event:'):
				logging.debug('Event message received: \n %s' %msg)
				self.event = message.Event(msg)
				logging.debug('Event object created successfully \n %s' %self.event.serialize())
			else:
				logging.debug('Unknown Message received: \n%s' %msg)
		
	def process(self):		
		"""Process incomming packets"""		
		self.read_packets()
		self.dispatch_packets()	
			
	def run(self):
		looping = True
		while looping:
			try:				
				self.process()				
			except KeyboardInterrupt:
				logging.warn('Disconnecting from server:%s' %(self.asterisksrv))
				self.disconnect()
				break

if __name__ == "__main__":
	#clear old log file 
	if os.path.exists('myapp.log'): os.remove('myapp.log')
	#Enable logging for debugging
	logging.basicConfig(format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', 
						filename='myapp.log', level=logging.DEBUG)
	logger = logging.getLogger(__name__)

	client = AstBridgeManager('localhost', 5038, 'trungvo', 'abc@123')
	client.run()


